//Names: Krystal Thomason and Ben Orr
//Assignment: Client and Server Multithreading
//File: Client_main.cpp
//Description: This is the client of a client server chat. It takes in a 
//server and a port. It sends out and retrives message from sockets

#include <string>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>  /* define socket */
#include <netinet/in.h>  /* define internet socket */
#include <netdb.h>       /* define internet socket */
#include <unistd.h>      //Might have been/is being used for a print function
#include <arpa/inet.h>   //used for address handling
#include <signal.h>      //signal interrupts  

using namespace std;

const string QUIT = "/quit\n";
const string EXIT = "/exit\n";
const string PART = "/part\n";
pthread_mutex_t mutex1=PTHREAD_MUTEX_INITIALIZER;  //for securing critical   
                                                   //areas
struct thread_info    //this was necessary to pass info to thread
{
  char * buffer;   //may not actually be needed now
  int socks;
};


void signal_intercept(int sig);
void* thread_read(void* info);



int main()
{
  char buf_read[1028];
  string ports;
  string server2;
  int temp;
  int portno=7744;
  int sockfd, n;
  struct sockaddr_in serv_addr;
  struct hostent *server;
  struct in_addr h_addr;
  struct thread_info bob,bob2; 
 
  signal(SIGINT, signal_intercept);

  cout<<"Welcome to the chat, what server would you like to connect to?"<<endl;
  cin>>server2;
  cout<<endl<<"Which port would you like to connect to?(0 for default)"<<endl;
  cin>>ports;
  portno=atoi(ports.c_str());
  if (portno == 0)
  {
    portno=7744;
    ports="7744";
  }
  else if (portno <= 1024 || portno >= 65535)
  {
    cout<<"Incorrect server selection,"<<endl<<
    "your port must be in the range of 1024-65535, exiting..."<<endl; 
     return 1;
  }

  //server2 = "rc04xcs213.managed.mst.edu";  

  sockfd = socket(AF_INET, SOCK_STREAM, 0);  //opens socket in ipv4
  if (sockfd < 0)
  {
    cerr<<"Error opening socket. Exiting..."<<endl;
    return 1;
  }

  if ((server=gethostbyname(server2.c_str()))==0)   //tries to get IP address 
  {                                                 //of server
    cerr<<"Error, can not retrive server info. Exiting..."<<endl;
    return 1;
  }
//this section puts all the port and address info into its proper place
//for the connect function to work

  h_addr.s_addr = *((unsigned long *) server->h_addr_list[0]); 
  memset(&serv_addr, 0, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = h_addr.s_addr;
  serv_addr.sin_port = htons(portno);
  
// connects to the server
  if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))< 0)
  {
    cerr<<"The connection to the server failed. Exiting..."<<endl;
    return 1;
  }

  cout<<"The Server has connnected!"<<endl;
  cout<<"What would you like to say?"<<endl;

  bzero(buf_read,1028);  //readies the buffer
  pthread_t read_thread;  //creates the read thread
  bob.socks=sockfd;   //init the struct
  bob.buffer=buf_read;
  //starts the read thread
  pthread_create(&read_thread,NULL, &thread_read, static_cast<void*>(&bob));

  // This loop does the write function

  while( (fgets((bob.buffer),1027,stdin))) //reads in until there is no
  {                                        //more input to the keyboard
    pthread_mutex_lock(&mutex1);
    n=write(sockfd, (bob.buffer), strlen(bob.buffer)-1);
    
    if (bob.buffer==QUIT || bob.buffer==EXIT || bob.buffer==PART)
    {
      cout<<"Exiting...."<<endl;  //checks for exit message after sending to 
      return 0;                   // to the server
    }
    bzero((bob.buffer),1028);     //clears the buffer
    
    pthread_mutex_unlock(&mutex1);

    if(n<0)
    {
      //Only known to occur when connection to the server has been lost
      cerr<<"Error, cannot send message! The connection to the server has been lost."<<endl;
    }
    

  }
  //closes the socket
  close(sockfd);
  return 0;
}


void* thread_read(void* info)
{
  //makes the info readable
  thread_info* bob2 = static_cast<thread_info*>(info);
  int sock=bob2->socks;
  int i;
  //char* buff= bob2->buffer;
  while((read(sock,(bob2->buffer),1028))>0) //reads from socket as long as
  {                                         //there are things to read.
   
    printf("%s\n",(bob2->buffer));
    bzero((bob2->buffer),1028);  //need to clear the buffer afterwards

  }
  close(sock);
}

void signal_intercept(int sig)
{
  if(sig==SIGINT) 
  {
    cout<<"Please use /exit, /quit, or /part to exit chat."<<endl;
  }
}




